package org.bdware.doip.core.codec.packet;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import org.apache.log4j.Logger;
import org.bdware.doip.core.doipMessage.DoipMessage;
import org.bdware.doip.core.doipMessage.MessageEnvelope;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class PacketNettyTCPCodec extends MessageToMessageCodec<ByteBuf, DoipMessage> {

    Logger logger = Logger.getLogger(PacketNettyTCPCodec.class);
    PacketMessageCodec codec = new PacketMessageCodecImpl();
    HashMap<Integer,AbstractEnvelopeReceiveBuffer> receiveBufferMap = new HashMap<>();

    @Override
    protected void encode(ChannelHandlerContext ctx, DoipMessage msg, List<Object> out){
        logger.debug("encoding DOIP message to byteBuffer,msg body length: " + msg.body.getEncodedData().length);
        try {
            if (msg.getMTU() < Integer.MAX_VALUE) {
                logger.info("MTU suggested to be max,change MTU to Integer.MAX_VALUE");
                msg.setMTU(Integer.MAX_VALUE);
            }
            ByteBuf buff = Unpooled.directBuffer();
            ArrayList<MessageEnvelope> envelpoes = codec.MessageToEnvelopes(msg);
            for(MessageEnvelope env:envelpoes){
                buff.writeBytes(codec.EnvelopeToBytes(env));
            }
            logger.debug("finish encoding, length: " + buff.readableBytes());
            out.add(buff);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out){
        logger.debug("decoding byteBuffer to DOIP message");
        try {

            byte[] envBytes = new byte[msg.readableBytes()];
            msg.readBytes(envBytes);
            MessageEnvelope envelope = codec.BytesToEnvelope(envBytes);
            AbstractEnvelopeReceiveBuffer recvBuffer = receiveBufferMap.get(envelope.requestId);
            if(recvBuffer == null){
                recvBuffer = new NoResendEnvelopeReceiveBuffer(envelope.requestId,ctx);
                receiveBufferMap.put(envelope.requestId,recvBuffer);
            }
            recvBuffer.addEnvelope(envelope);
            if(recvBuffer.isCompleted()){
                ArrayList<MessageEnvelope> envList = recvBuffer.getSortedEnvelopes();
                out.add(codec.EnvelopesToMessage(envList));
                receiveBufferMap.remove(envelope.requestId);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

}
